#ifndef __TRIANGLE_H__
#define __TRIANGLE_H__

#include <llib.h>

#include <list>

using namespace llib;
using namespace llib::geom;
using namespace llib::math;
using namespace std;

#ifndef TRIANGLE3F
#define TRIANGLE3F

template <typename T>
class Vector3 {
public:
	union {
		struct { T x, y, z; };
		struct { T cell[3]; };
	};
};

typedef Vec3f                       Vector3f;
typedef Vec3i                       Vector3i;
typedef Vec2f                       Vector2f;

typedef Vector3<Vector2f>			Triangle3f_2D;
typedef Vector3<Vector3f>			Triangle3f;
typedef Vector3<Vector3i>			Triangle3i;
typedef Vector3< Vector3<Boolean> >		Triangle3b;

#endif

enum CollisionStatus {
	COLLISION_UNKNOWN,
	COLLISION_INTERSECTION,
	COLLISION_FREE
};

enum CollisionType{
	COLLISION_TYPE_UNKNOWN,
	COLLISION_TYPE_VF,
	COLLISION_TYPE_EE,
	COLLISION_TYPE_BOUND
};

class CollisionInstant;
bool cmp_CollisionInstant( const CollisionInstant &l, const CollisionInstant &r );

class CollisionInstant {
public:
	Float			TimePoint;
	CollisionType	Type;
	// we calculate the point index of TriangleList[tid].cell[pid] as:
	//		PointId = tid * 3 + pid
	// Type == COLLISION_TYPE_VF:
	//		V:p0,	F: p1, p2, p3
	// Type == COLLISION_TYPE_EE:
	//		firset E: p0, p1,  second E: p2, p3
	// Type == COLLISION_TYPE_BOUND:
	//		out of bound point: p0, other is undifined
	Uint16			p0, p1, p2, p3;

	friend bool operator < (const CollisionInstant &l, const CollisionInstant &r) { return cmp_CollisionInstant(l,r); }
};

class TrianglePairTester {
public:
	static vector<CollisionInstant>
		TestDynamic(const Float deltaT, Triangle3f &firstLoc, Triangle3f &firstV, Triangle3f &secondLoc, Triangle3f &secondV);
	static Boolean
		TestStatic(Triangle3f &firstLoc, Triangle3f &secondLoc);
private:
	const static Int16 VFtestVertexMap[6][4];
	const static Int16 EEtestVertexMap[9][4];

	inline static Float determinantValue(Vector3f &first, Vector3f &second, Vector3f &third);

	static vector<Float>
		DynamicVFtest(Float deltaT, Vector3f &p0, Vector3f &p1, Vector3f &p2, Vector3f &p3, Vector3f &v0, Vector3f &v1, Vector3f &v2, Vector3f &v3);
	static vector<Float>
		DynamicEEtest(Float deltaT, Vector3f &p0, Vector3f &p1, Vector3f &p2, Vector3f &p3, Vector3f &v0, Vector3f &v1, Vector3f &v2, Vector3f &v3);
	static vector<Float>
		CoplanarTest(Vector3f &p0, Vector3f &p1, Vector3f &p2, Vector3f &p3, Vector3f &v0, Vector3f &v1, Vector3f &v2, Vector3f &v3);
	static void
		ClampCoplanarCandidate(vector<Float> &candidates, Float deltaT);
	static Boolean
		PointInsideTriangle(Triangle3f &triangle, Vector3f &p);
	static Boolean
		PointInsideTriangle(Triangle3f_2D &triangle, Vector2f &p);
	static Boolean
		SegmentCross(Vector3f &p0_start, Vector3f &p0_end, Vector3f &p1_start, Vector3f &p1_end);
	static Boolean
		TriangleTriangleIntersection_2D(Triangle3f_2D &firstT, Triangle3f_2D &secondT);

};



#endif